﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

using ZetaPrints.ZetaClient.Data;
using ZetaPrints.ZetaClient.Data.Repository.Linq;
using ZetaPrints.ZetaClient.Shared;
using ZetaPrints.ZetaClient.Business.ThreadSubSytem;

namespace ZetaPrints.ZetaClient.Business
{
    /// <summary>
    /// This class takes care of all the files to be taken
    /// care of
    /// </summary>
    [DebuggerDisplay("{OrderFileDetailEntry.WebPath}")]
    public class FileManager:BaseManager
    {
        #region public properties
        /// <summary>
        /// The data for this file
        /// </summary>
        public OrderFileDetail OrderFileDetailEntry { get; set; }
        /// <summary>
        /// Have this entry ever been downloaded?
        /// </summary>
        public bool FileExistsLocaly
        {
            get
            {
                bool fileExistsLocaly = false;

                if (OrderFileDetailEntry.LocalPath != null)
                {
                    if (OrderFileDetailEntry.LocalPath.Length > 0)
                    {
                        fileExistsLocaly = true;
                    }
                }

                return fileExistsLocaly;
            }
        }
        /// <summary>
        /// If this file is considered a image file
        /// </summary>
        public bool IsImage
        {
            get
            {
                bool isImage = false;

                /// list of accetable extensions for image
                List<string> accetableExtensions = new List<string>{
                    "jpg",
                    "jpeg",
                    "jpe",
                    "jfif",
                    "gif",
                    "tif",
                    "tiff",
                    "png",
                    "ico"};

                /// go throught he extensions
                foreach (string extension in accetableExtensions)
                {
                    if (OrderFileDetailEntry.WebPath.ToLower().EndsWith(extension))
                    {
                        isImage = true;
                        break;
                    }
                }

                return isImage;
            }
        }
        /// <summary>
        /// Gets the full local path of the file.
        /// </summary>
        public string FullLocalPath
        {
            get
            {
                string fullLocalPath = string.Empty;

                if (OrderFileDetailEntry.LocalPath != null)
                {
                    /// this is not a full path, create one
                    if (!OrderFileDetailEntry.LocalPath.Contains(":") &&
                        !OrderFileDetailEntry.LocalPath.Contains(@"\\"))
                    {
                        if ((!ZetaClientConfiguration.CurrentApplicationLocation.EndsWith(@"\")) &&
                            (!OrderFileDetailEntry.LocalPath.StartsWith(@"\")))
                        {
                            fullLocalPath = ZetaClientConfiguration.CurrentApplicationLocation + @"\" + OrderFileDetailEntry.LocalPath;
                        }
                        else
                        {
                            fullLocalPath = ZetaClientConfiguration.CurrentApplicationLocation + OrderFileDetailEntry.LocalPath;
                        }
                    }
                    else
                    {
                        fullLocalPath = OrderFileDetailEntry.LocalPath;
                    }
                }

                return fullLocalPath;
            }
        }
        /// <summary>
        /// Just get if this guy is running anything.
        /// </summary>
        /// <returns></returns>
        public override bool AreThreadsAlive
        {
            get
            {
                return ThreadManager.AreThreadsAlive;
            }
        }
        #endregion


        #region consturctors
        /// <summary>
        /// Initialize the file manager system
        /// </summary>
        /// <param name="site"></param>
        /// <param name="orderFileDetail"></param>
        public FileManager(Site site, OrderFileDetail orderFileDetail)
            : base(site)
        {
            OrderFileDetailEntry = orderFileDetail;
        }
        /// <summary>
        /// Initialize the file manager system
        /// </summary>
        /// <param name="site"></param>
        /// <param name="orderId"></param>
        /// <param name="fileIndex"></param>
        public FileManager(Site site, Guid orderId, int fileIndex)
            : base(site)
        {
            OrderFileDetailEntry = _dataRepositoryManager.FetchOrderFileDetail(orderId, fileIndex);
        }
        /// <summary>
        /// Initialize the file manager system
        /// </summary>
        /// <param name="siteName">the name of the site</param>
        /// <param name="orderFileDetail"></param>
        public FileManager(string siteName, OrderFileDetail orderFileDetail)
            : base(siteName)
        {
            OrderFileDetailEntry = orderFileDetail;
        }
        /// <summary>
        /// Initialize the file manager system
        /// </summary>
        /// <param name="siteName">the name of the site</param>
        /// <param name="orderId"></param>
        /// <param name="fileIndex"></param>
        public FileManager(string siteName, Guid orderId, int fileIndex)
            : base(siteName)
        {
            OrderFileDetailEntry = _dataRepositoryManager.FetchOrderFileDetail(orderId, fileIndex);
        }
        #endregion


        #region private methods
        /// <summary>
        /// Gets and saves the order file
        /// </summary>
        /// <param name="order"></param>
        /// <param name="forceDownloadAllAtachments"></param>
        private void DownloadFileThread(object forceDownloadAllAtachmentsObject)
        {
            SendMessage(MessageTypeOption.Message, "Downloading file " + OrderFileDetailEntry.FileName);

            bool forceDownloadAllAtachments = (bool)forceDownloadAllAtachmentsObject;

            ZetaClientConfiguration zetaClientConfiguration = new ZetaClientConfiguration();

            /// create the directory if it does not already exist to store all the files
            string directoryName = zetaClientConfiguration.DownloadRootDirectory + @"\" + OrderFileDetailEntry.OrderId + @"\";

            if (!System.IO.Directory.Exists(directoryName))
            {
                System.IO.Directory.CreateDirectory(directoryName);
            }

            /// acceptable extensions to download
            List<string> acceptedExtensions = new List<string>(zetaClientConfiguration.DownloadFileExtensions.Split(','));

            /// if the only entry here the default entry?
            /// If yes remove it.
            if (acceptedExtensions.Count == 1)
            {
                if (acceptedExtensions[0] == string.Empty)
                {
                    acceptedExtensions.RemoveAt(0);
                }
            }


            if (OrderFileDetailEntry.WebPath != null)
            {
                if (OrderFileDetailEntry.WebPath != string.Empty)
                {
                    bool downloadFile = true;

                    /// do we have any acceptable extension?
                    if (acceptedExtensions.Count > 0)
                    {
                        /// now it has to pass the test to be downloaded
                        downloadFile = false;

                        /// get the current extension
                        string extension = OrderFileDetailEntry.WebPath.Substring(OrderFileDetailEntry.WebPath.IndexOf('.') + 1);

                        foreach (string acceptExtension in acceptedExtensions)
                        {
                            /// do we have a qualified extension?
                            if (extension == acceptExtension)
                            {
                                downloadFile = true;
                                break;
                            }
                        }
                    }
                    if (downloadFile)
                    {
                        if (_webAction.GetFile(OrderFileDetailEntry.WebPath))
                        {
                            /// if our name is emtpy create one. If not we
                            /// are going to override whatever is point to this entry
                            if ((OrderFileDetailEntry.LocalPath == null) || (OrderFileDetailEntry.LocalPath.Length == 0))
                            {
                                OrderFileDetailEntry.LocalPath = directoryName + OrderFileDetailEntry.Name;

                                /// save the changes
                                _dataRepositoryManager.SubmitChanges();

                                _dataRepositoryManager.SaveOrderFileDetailLocalPath(OrderFileDetailEntry.OrderId,
                                    OrderFileDetailEntry.FileIndex,
                                    directoryName + OrderFileDetailEntry.Name);
                            }

                            _webAction.SaveData(OrderFileDetailEntry.LocalPath);


                            SendMessage(MessageTypeOption.Message, "Download completed of " + OrderFileDetailEntry.WebPath);
                        }
                        else
                        {
                            SendMessage(MessageTypeOption.Message, "File not found:" + OrderFileDetailEntry.WebPath);
                        }
                    }
                }
            }

            /// send message that an file for the order id is done
            SendMessage(MessageTypeOption.DownloadFileThread, OrderFileDetailEntry.OrderId.ToString());
        }
        #endregion


        #region public methods
        /// <summary>
        /// Starts a thread to download the file, the Message with DownloadFileThread will come with 
        /// the order id as the message
        /// </summary>
        /// <param name="forceDownloadAllAtachments"></param>
        public void DownloadFile(bool forceDownload)
        {
            Thread thread = new Thread(new ParameterizedThreadStart(DownloadFileThread));
            ThreadManager.AddThread(OrderFileDetailEntry.OrderId, ThreadActionOption.DownloadFile, thread, forceDownload);
        }
        /// <summary>
        /// Moves or copies the file depending if this is an exclusive file, 
        /// if yes the file will be moved, if not the file will be copied.
        /// </summary>
        /// <param name="source">where the file is coming from</param>
        /// <param name="destination">where the file is going</param>
        /// <returns></returns>
        public bool MoveFile(string source, string destination)
        {
            ZetaClientConfiguration zetaClientConfiguration = new ZetaClientConfiguration();

            string dbSource = zetaClientConfiguration.NormalizeFileWithDownloadRootDirectory(source);
            string dbDestination = zetaClientConfiguration.NormalizeFileWithDownloadRootDirectory(destination);

            bool fileMoved = false;

            /// if we actually got a new name do we go
            /// throught he trouble of changing it
            if (destination != source)
            {
                /// change the database entry.
                _dataRepositoryManager.ChangeFileDetailLocalPath(OrderFileDetailEntry.OrderId, OrderFileDetailEntry.FileIndex, 
                    dbSource, dbDestination);

                /// do we have a file to move?
                if (System.IO.File.Exists(source))
                {
                    /// create connection to file
                    System.IO.FileInfo fileInfo = new System.IO.FileInfo(source);

                    /// if the file already exist we need
                    /// to overrite it
                    if (File.Exists(destination))
                    {
                        if (File.Exists(destination + ".Old"))
                        {
                            File.Delete(destination + ".Old");
                        }
                        File.Move(destination, destination + ".Old");
                    }

                    /// if this is a exclusive file we move it, or else
                    /// we will only make a copy elsewhere
                    if (_dataRepositoryManager.IsExclusiveFile(dbSource))
                    {
                        fileInfo.MoveTo(destination);
                    }
                    else
                    {
                        fileInfo.CopyTo(destination);
                    }

                    fileMoved = true;
                }

                /// did the move work
                if (fileMoved)
                {
                    _dataRepositoryManager.SubmitChanges();
                }
            }
            else
            {
                /// sure whatever, if going to the same place
                /// was your objective go you.
                fileMoved = true;
            }

            return fileMoved;
        }
        /// <summary>
        /// Gets the image entry if this is an image
        /// file, if not will return null
        /// </summary>
        public Image GetImageThumbnail(int height, int width)
        {
            Image image = null;
            if ((IsImage) && (File.Exists(FullLocalPath)))
            {
                image = new Bitmap(FullLocalPath);

                /// now lets see how wins, we need to make the thumbnail
                /// fit on the heigh and width given
                int widthCalculated = (int)(height * ((float)image.Width / (float)image.Height));
                int heighCalculated = (int)(width * ((float)image.Height / (float)image.Width));

                if (widthCalculated > width)
                {
                    widthCalculated = width;
                }
                if( heighCalculated > height)
                {
                    heighCalculated = height;
                }

                /// if we have acceptable width and height we are set
                if ((widthCalculated > 0) && (heighCalculated > 0))
                {
                    image = image.GetThumbnailImage(widthCalculated, heighCalculated, null, System.IntPtr.Zero);
                }
            }
            return image;
        }
        #endregion
    }
}
